在Spring之前的一些版本中,用户需要在web应用程序上下文中定义一个或多个HandlerMapping将进来的web请求映射到合适的处理器。在引入了被注解的控制器后,你不再需要这么做,因为RequestMappingHandlerMapping会自动在所有的@Controllerbean上查找@ReqeuestMapping。然而,请机组所有的HandlerMapping类都继承自AbstractHandlerMapping,都有下列的属性,你可以利用这些属性来定制它们的行为: interceptors:使用的拦截器的列表。HandlerInterceptors会在22.4.1节,"Intercepting requests with a HandlerInterceptor"中讨论。
defaultHandler:默认使用的处理器,当不存在匹配的处理器时,会使用默认的处理器。
order:取决于order属性(见org.springframework.core.Order接口),Spring会将上下文中所有可用的处理器排序,并应用第一个符合的处理器。
alwaysUseFullPath:如果为true,Spring使用当前Servlet上下文中的完整路径来查找合适的处理程序。如果是false(默认值),当前Servlet上下文中映射的路径会被使用。比如,如果一个Servlet映射到/testing/*,并且alwaysUseFullPath属性被设为true,那么/testing/viewPage.html会被使用,相反的如果这个属性被设为false,那么/viewPage.html会被使用。
* urlDecode:从Spring2.5开始,默认值为true。如果你想要比较编码路径,将其设置为false。然而,HttpServletRequest总是会以解码的形式暴露出Servlet路径。注意比较编码的路径时,Servlet路径可能不匹配。

下面的例子展示了如何配置一个拦截器:

<beans>
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
        <property name="interceptors">
            <bean class="example.MyInterceptor"/>
        </property>
    </bean>
<beans>

22.4.1 Intercepting requests with a HandlerInterceptor

Spring的处理器包括拦截器的映射机制,在你想要自动引用某些特定的功能到一些请求时十分有用,比如,某个重要的检查。
拦截器必须要实现org.springframework.web.servlet包中的HandlerInterceptor接口。这个接口定义了三个方法:preHandle(..)会在实际的处理器执行前执行;postHandle(..)会在处理器执行之后执行;afterCompetion(..)会在请求被完整的处理完之后执行。这三种方法为所有的前置处理和后置处理提供了足够的灵活性。
preHandle(..)方法返回了一个boolean值。你可以利用这个方法去中断或是继续执行链。当一个方法返回true时,处理器执行链会继续;当这个方法返回false时,DispatcherServlet会认为拦截器自己完成了请求的处理(比如,渲染了一个合适的视图),不会再执行执行链中的其他的拦截器和实际的处理器。
拦截器可以使用interceptors属性配置,这个属性存在于所有继承自AbstractHandlerMappingHandlerMapping类中。下面是一个例子:

<beans>
    <bean id="handlerMapping"
            class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
        <property name="interceptors">
            <list>
                <ref bean="officeHoursInterceptor"/>
            </list>
        </property>
    </bean>

    <bean id="officeHoursInterceptor"
            class="samples.TimeBasedAccessInterceptor">
        <property name="openingTime" value="9"/>
        <property name="closingTime" value="18"/>
    </bean>
</beans>
package samples;

public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {

    private int openingTime;
    private int closingTime;

    public void setOpeningTime(int openingTime) {
        this.openingTime = openingTime;
    }

    public void setClosingTime(int closingTime) {
        this.closingTime = closingTime;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        Calendar cal = Calendar.getInstance();
        int hour = cal.get(HOUR_OF_DAY);
        if (openingTime <= hour && hour < closingTime) {
            return true;
        }
        response.sendRedirect("http://host.com/outsideOfficeHours.html");
        return false;
    }
}

这个映射处理的任何请求都会被TimeBasedAccessInterceptor拦截。如果当前时间不在工作时间内,用户会被重定向到静态的页面,比如,显示你只能在官方时间内访问官网。

当使用ReqeustMappingHandlerMapping时,实际的处理器是HandlerMethod的一个实例,它定义了具体调用的控制器方法。

正如你所见的,Spring适配器类HandlerInterceptorAdapter让继承HandlerInterceptor接口变得简单。

在上面的例子中,配置的拦截器会自动的应用到所有的被注解的控制器方法上。如果你希望缩小拦截器应道的URL路径,你可以使用MVC命名空间或是MVC Java配置,或是声明一个MappedInterceptor类型的实例。见22.16.1节,"Enabling the MVC Java Config or the MVC XML Namespace"
注意HandlerInterceptorpostHandle方法并不总是合适@ResponseBodyResponseEntity的方法。在这种情况下,HttpMessageConverter会在postHandle调用前写入和提交相响应,这会呆滞无法修改响应,比如添加一个响应头。可以让应用程序实现ResponseBodyAdvice或是为它声明一个@COntrollerAdvice,在或者就是直接在RequestMappingHandlerAdapter中配置。